//===--- Integers.swift.gyb -----------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
 %{
#
# Utility code for later in this template
#

from string import maketrans, capitalize

# Number of bits in the Builtin.Word type
word_bits = int(CMAKE_SIZEOF_VOID_P) * 8

# Number of bits in integer literals.
builtinIntLiteralBits = 2048
IntLiteral = 'Int%s' % builtinIntLiteralBits

class struct(object):
  def __init__(self, **kw):
    self.__dict__ = kw
  def __repr__(self):
    return 'struct(%r)' % self.__dict__

binaryArithmetic = {
  'Arithmetic' : [
    struct(operator='+', name='adding',      mutatingName='add',      firstArg='_',  llvmName='add', kind='+'),
    struct(operator='-', name='subtracting', mutatingName='subtract', firstArg='_',  llvmName='sub', kind='-'),
    struct(operator='*', name='multiplied',  mutatingName='multiply', firstArg='by', llvmName='mul', kind='*'),
    struct(operator='/', name='divided',     mutatingName='divide',   firstArg='by', llvmName='div', kind='/'),
  ],
  'BinaryInteger' : [
    struct(operator='%', name='remainder',   mutatingName='formRemainder', firstArg='dividingBy', llvmName='rem', kind='/'),
  ],
}

binaryBitwise = [
    struct(operator='&', name='bitwiseAnd', llvmName='and'),
    struct(operator='|', name='bitwiseOr', llvmName='or'),
    struct(operator='^', name='bitwiseXor', llvmName='xor'),
]

maskingShifts = [
    struct(
      operator='&>>', nonMaskingOperator='>>', description='right shift',
      name='maskingShiftRight', llvmName=lambda s:['lshr','ashr'][s]),
    struct(
      operator='&<<', nonMaskingOperator='<<', description='left shift',
      name='maskingShiftLeft', llvmName=lambda _: 'shl'),
]
}%

infix operator &<< : BitwiseShiftPrecedence
infix operator &<<= : AssignmentPrecedence
infix operator &>> : BitwiseShiftPrecedence
infix operator &>>= : AssignmentPrecedence

//===----------------------------------------------------------------------===//
//===--- Bits for the Stdlib ----------------------------------------------===//
//===----------------------------------------------------------------------===//


// FIXME(integers): This should go in the stdlib separately, probably.
extension ExpressibleByIntegerLiteral
  where Self : _ExpressibleByBuiltinIntegerLiteral {
  /// Create an instance initialized to `value`.
  @_transparent
  public init(integerLiteral value: Self) {
    self = value
  }
}

//===----------------------------------------------------------------------===//
//===--- Arithmetic -------------------------------------------------------===//
//===----------------------------------------------------------------------===//

/// Declares methods backing binary arithmetic operators—such as `+`, `-` and
/// `*`—and their mutating counterparts.
///
/// It provides a suitable basis for arithmetic on scalars such as integers and
/// floating point numbers.
///
/// Both mutating and non-mutating operations are declared in the protocol,
/// however only the mutating ones are required, as default implementations of
/// the non-mutating ones are provided by a protocol extension.
///
/// The `Magnitude` associated type is able to hold the absolute value of any
/// possible value of `Self`. Concrete types do not have to provide a typealias
/// for it, as it can be inferred from the `magnitude` property. This property
/// can be useful in operations that are simpler to implement in terms of
/// unsigned values, for example, printing a value of an integer, which is just
/// printing a '-' character in front of an absolute value.
///
/// Please note that for ordinary work, the `magnitude` property **should not**
/// be preferred to the `abs(_)` function, whose return value is of the same
/// type as its argument.
public protocol Arithmetic : Equatable, ExpressibleByIntegerLiteral {
  // FIXME(integers): implement
  //init?<T : BinaryInteger>(exactly source: T)

  // FIXME(ABI)#44 (Recursive Protocol Constraints): should be just Arithmetic
  associatedtype Magnitude : Equatable, ExpressibleByIntegerLiteral

  var magnitude: Magnitude { get }


% for x in binaryArithmetic['Arithmetic']:
  // defaulted using an in-place counterpart, but can be used as an
  // optimization hook
  func ${x.name}(${x.firstArg} rhs: Self) -> Self

  // implementation hook
  mutating func ${x.mutatingName}(${x.firstArg} rhs: Self)
% end
}

extension Arithmetic {
  @_transparent
  public init() {
    self = 0
  }
}

% for Protocol in binaryArithmetic:
extension ${Protocol} {
%   for x in binaryArithmetic[Protocol]:
%     callLabel = x.firstArg + ': ' if not x.firstArg == '_' else ''
  public func ${x.name}(${x.firstArg} rhs: Self) -> Self {
    var lhs = self
    lhs.${x.mutatingName}(${callLabel}rhs)
    return lhs
  }
%   end
}
% end

public protocol SignedArithmetic : Arithmetic {
  func negated() -> Self
  mutating func negate()
}

extension SignedArithmetic {
  public func negated() -> Self {
    return Self().subtracting(self)
  }
  public mutating func negate() {
    self = negated()
  }
}

//===----------------------------------------------------------------------===//
//===--- Arithmetic operators ---------------------------------------------===//
//===----------------------------------------------------------------------===//

% for Protocol in binaryArithmetic:
%   for x in binaryArithmetic[Protocol]:
%     callLabel = x.firstArg + ': ' if not x.firstArg == '_' else ''
@_transparent
public func ${x.operator} <T: ${Protocol}>(lhs: T, rhs: T) -> T {
  return lhs.${x.name}(${callLabel}rhs)
}

@_transparent
public func ${x.operator}= <T: ${Protocol}>(lhs: inout T, rhs: T) {
  lhs.${x.mutatingName}(${callLabel}rhs)
}
%   end
% end

@_transparent
public prefix func - <T: SignedArithmetic>(x: T) -> T {
  return x.negated()
}

//===----------------------------------------------------------------------===//
//===--- BinaryInteger ----------------------------------------------------===//
//===----------------------------------------------------------------------===//

public protocol BinaryInteger :
  Comparable, Arithmetic, CustomStringConvertible {

  static var isSigned: Bool { get }

  // Dispatching through these puts less stress on the user reading
  // the interface and error messages (and on the type checker) than
  // does having many operator overloads.
  func isEqual(to rhs: Self) -> Bool
  func isLess(than rhs: Self) -> Bool

  init?<T : FloatingPoint>(exactly source: T)

  init<T : FloatingPoint>(_ source: T)

  init<T : BinaryInteger>(_ source: T)

  init<T : BinaryInteger>(extendingOrTruncating source: T)

  init<T : BinaryInteger>(clamping source: T)

  func word(at n: Int) -> UInt

  var bitWidth : Int { get }

  var minimumSignedRepresentationBitWidth: Int { get }

% for x in binaryArithmetic['BinaryInteger']:
  // defaulted using an in-place counterpart, but can be used as an
  // optimization hook
  func ${x.name}(${x.firstArg} rhs: Self) -> Self

  // implementation hook
  mutating func ${x.mutatingName}(${x.firstArg} rhs: Self)
% end

  func quotientAndRemainder(dividingBy rhs: Self) -> (Self, Self)

  /// Returns `-1` if the value of `self` is negative, `1` if it's positive,
  /// `0` otherwise.
  func signum() -> Self
}

extension BinaryInteger {
  public init?<T : FloatingPoint>(exactly source: T) {
    // FIXME(integers): implement
    fatalError()
    return nil
  }

  public init<T : FloatingPoint>(_ source: T) {
    // FIXME(integers): implement
    fatalError()
  }

  public func signum() -> Self {
    // FIXME(integers): implement
    fatalError()
  }

  public var countRepresentedWords: Int {
    return (self.bitWidth + ${word_bits} - 1) / ${word_bits}
  }

  public func quotientAndRemainder(dividingBy rhs: Self) -> (Self, Self) {
    return (self.divided(by: rhs), self.remainder(dividingBy: rhs))
  }
}

//===----------------------------------------------------------------------===//
//===--- Homogeneous comparison -------------------------------------------===//
//===----------------------------------------------------------------------===//

@_transparent
public func == <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return lhs.isEqual(to: rhs)
}

@_transparent
public func < <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return lhs.isLess(than: rhs)
}

//===----------------------------------------------------------------------===//
//===--- Heterogeneous comparison -----------------------------------------===//
//===----------------------------------------------------------------------===//

@_transparent
public func == <T : BinaryInteger, U : BinaryInteger>(lhs: T, rhs: U) -> Bool {
  return (lhs > 0) == (rhs > 0)
    && T(extendingOrTruncating: rhs) == lhs
    && U(extendingOrTruncating: lhs) == rhs
}

@_transparent
public func != <T : BinaryInteger, U : BinaryInteger>(lhs:T, rhs: U) -> Bool {
  return !(lhs == rhs)
}

@_transparent
public func < <T : BinaryInteger, U : BinaryInteger>(lhs: T, rhs: U) -> Bool {
  let lhsSign = lhs < 0 ? -1 : lhs > 0 ? 1 : 0
  let rhsSign = rhs < 0 ? -1 : rhs > 0 ? 1 : 0
  if lhsSign != rhsSign { return lhsSign < rhsSign }

  // if we get here, lhs and rhs have the same sign.  If they're
  // negative, then T and U are both signed types, and one of them can
  // represent values of the other type.  Otherwise, lhs and rhs are
  // positive, and one of T, U may be signed and the other unsigned.
  // In this case, we can conceptually subtract 1 from the bitWidth of
  // any signed type, and either the resulting bitWidths are the same
  // or one can represent every value of the other.

  let rT = T(extendingOrTruncating: rhs)

  // Can we round-trip rhs through T?
  if U(extendingOrTruncating: rT) == rhs {
    return lhs < rT
  }

  return U(extendingOrTruncating: lhs) < rhs
}

@inline(__always)
public func <= <T : BinaryInteger, U : BinaryInteger>(lhs: T, rhs: U) -> Bool {
  return !(rhs < lhs)
}

@inline(__always)
public func >= <T : BinaryInteger, U : BinaryInteger>(lhs: T, rhs: U) -> Bool {
  return !(lhs < rhs)
}

@inline(__always)
public func > <T : BinaryInteger, U : BinaryInteger>(lhs: T, rhs: U) -> Bool {
  return rhs < lhs
}

//===----------------------------------------------------------------------===//
//===--- Ambiguity breakers -----------------------------------------------===//
// These two versions of the operators are not ordered with respect to
// one another:
//
//     <T : Comparable>(T, T) -> Bool
//     <T : BinaryInteger, U : BinaryInteger>(T, U) -> Bool
//
// so we define:
//
//     <T : BinaryInteger>(T, T) -> Bool
//===----------------------------------------------------------------------===//

@_transparent
public func != <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return !(lhs == rhs)
}

@inline(__always)
public func <= <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return !(rhs < lhs)
}

@inline(__always)
public func >= <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return !(lhs < rhs)
}

@inline(__always)
public func > <T : BinaryInteger>(lhs: T, rhs: T) -> Bool {
  return rhs < lhs
}

//===----------------------------------------------------------------------===//
//===--- FixedWidthInteger ------------------------------------------------===//
//===----------------------------------------------------------------------===//

public enum ArithmeticOverflow {
  @_transparent
  public init(_ overflow: Bool) { self = overflow ? .overflow : .none }
  case none, overflow
}

public protocol FixedWidthInteger : BinaryInteger {
  static var bitWidth : Int { get }

  static var max: Self { get }
  static var min: Self { get }

% for x in binaryArithmetic['Arithmetic']:
%{
comment = '''
  /// Return a pair consisting of `self` {} `rhs`,
  /// truncated to fit if necessary, and a flag indicating whether an
  /// arithmetic overflow occurred.'''.format(x.operator) + ('''
  ///
  /// - Precondition: `rhs != 0`''' if x.kind == '/' else '')
}%
${comment}
  func ${x.name}WithOverflow(
    ${x.firstArg} rhs: Self
  ) -> (partialValue: Self, overflow: ArithmeticOverflow)
% end

% for x in binaryBitwise + maskingShifts:
  func ${x.name}(_ rhs: Self) -> Self
% end

  static func doubleWidthMultiply(_ lhs: Self, _ rhs: Self)
    -> (high: Self, low: Magnitude)
  static func doubleWidthDivide(
    _ lhs: (high: Self, low: Magnitude), _ rhs: Self)
    -> (quotient: Self, remainder: Self)

  init(_truncatingBits bits: UInt)

  var popcount: Int { get }
  var leadingZeros: Int { get }
}

//===----------------------------------------------------------------------===//
//===--- Operators on FixedWidthInteger -----------------------------------===//
//===----------------------------------------------------------------------===//

@inline(__always)
public prefix func ~ <T: FixedWidthInteger>(x: T) -> T {
  return 0 &- x &- 1
}

% for x in binaryBitwise:
@_transparent
public func ${x.operator} <T: FixedWidthInteger>(lhs: T, rhs: T) -> T {
  return lhs.${x.name}(rhs)
}

@_transparent
public func ${x.operator}= <T: FixedWidthInteger>(lhs: inout T, rhs: T) {
  lhs = lhs.${x.name}(rhs)
}
% end

% for x in maskingShifts:

@_transparent
public func ${x.operator} <T: FixedWidthInteger>(lhs: T, rhs: T) -> T {
  return lhs.${x.name}(rhs)
}

@_transparent
public func ${x.operator}= <T: FixedWidthInteger>(lhs: inout T, rhs: T) {
  lhs = lhs ${x.operator} rhs
}

@_transparent
public func ${x.operator} <
  T: FixedWidthInteger, U: BinaryInteger
>(lhs: T, rhs: U) -> T {
  return lhs.${x.name}(T(extendingOrTruncating: rhs))
}

@_transparent
public func ${x.operator}= <
  T: FixedWidthInteger, U: BinaryInteger
>(lhs: inout T, rhs: U) {
  lhs = lhs ${x.operator} rhs
}

@_transparent
public func ${x.nonMaskingOperator} <
  T: FixedWidthInteger, U: BinaryInteger
>(lhs: T, rhs: U) -> T {
  // FIXME(integers): uncomment once Int conforms to BinaryInteger
  //let shift = rhs < -T.bitWidth ? -T.bitWidth
            //: rhs > T.bitWidth ? T.bitWidth
            //: Int(rhs)
  //return lhs ${x.nonMaskingOperator} shift
  fatalError()
}

//===----------------------------------------------------------------------===//
//=== "Smart ${x.description}", supporting overshifts and negative shifts -===//
//===----------------------------------------------------------------------===//

@_transparent
public func ${x.nonMaskingOperator} <
  T: FixedWidthInteger
>(lhs: T, rhs: Int) -> T {
  // FIXME(integers): uncomment once Int conforms to BinaryInteger
  fatalError()
  //let overshiftR = T.isSigned ? lhs &>> (T.bitWidth - 1) : 0
  //let overshiftL: T = 0
  //if _fastPath(rhs >= 0) {
    //if _fastPath(rhs < T.bitWidth) {
      //return lhs.${x.name}(T(extendingOrTruncating: rhs))
    //}
    //return overshift${'LR'['R' in x.name]}
  //}

  //if _slowPath(rhs <= -T.bitWidth) {
    //return overshift${'RL'['R' in x.name]}
  //}
  //return lhs ${x.operator.translate(maketrans('<>', '><'))} -rhs
}

@_transparent
public func ${x.nonMaskingOperator}= <
  T: FixedWidthInteger
>(lhs: inout T, rhs: T) {
  lhs = lhs ${x.nonMaskingOperator} rhs
}

@_transparent
public func ${x.nonMaskingOperator}= <
  T: FixedWidthInteger, U: BinaryInteger
>(lhs: inout T, rhs: U) {
  lhs = lhs ${x.nonMaskingOperator} rhs
}

% end # maskingShifts


extension FixedWidthInteger {
  public init<Other: BinaryInteger>(clamping source: Other) {
    if _slowPath(source < Self.min) {
      self = Self.min
    }
    else if _slowPath(source > Self.max) {
      self = Self.max
    }
    else { self = Self(extendingOrTruncating: source) }
  }

% for x in binaryArithmetic['Arithmetic']:
%   callLabel = x.firstArg + ': ' if not x.firstArg == '_' else ''
  @_transparent
  // FIXME(integers): rename `rhs` to `other`
  public mutating func ${x.mutatingName}(${x.firstArg} rhs: Self) {
    let (result, _ /*overflow*/) = self.${x.name}WithOverflow(${callLabel}rhs)
    // FIXME(integers): overflow check
    //_assertCond(overflow == .none, "overflow in ${x.name}")
    self = result
  }

  /// Return `self ${x.operator} rhs`.  If an arithmetic overflow
  /// occurs, the behavior is undefined.
  ///
  /// Note: use this function to avoid the cost of overflow checking
  /// when you are sure that the operation won't overflow.
  @_transparent
  public func unsafe${capitalize(x.name)}(rhs: Self) -> Self {
    let (result, overflow) = self.${x.name}WithOverflow(${callLabel}rhs)

    if (overflow != .none) {
      if (_isDebugAssertConfiguration()) {
        _preconditionFailure("overflow in unsafe${capitalize(x.name)}")
      }
      else {
        Builtin.conditionallyUnreachable()
      }
    }
    return result
  }
% end

  @_transparent
  public mutating func formRemainder(dividingBy other: Self) {
    // FIXME(integers): implement
    fatalError()
  }

  @_transparent
  public init<T : BinaryInteger>(extendingOrTruncating source: T) {
    if Self.bitWidth <= ${word_bits} {
      self = Self.init(_truncatingBits: source.word(at: 0))
    }
    else {
      var result: Self = source < 0 ? ~0 : 0
      // start with the most significant word
      var n = source.countRepresentedWords
      while n >= 0 {
        // masking is OK here because this we have already ensured
        // that Self.bitWidth > ${word_bits}.  Not masking results in
        // infinite recursion.
        result &<<= ${word_bits}
        result |= Self(_truncatingBits: source.word(at: n))
        n -= 1
      }

      self = result
    }
  }

  @_transparent
  // FIXME(integers): give it a better name. _highBitIndex is **NOT** what it is
  public // transparent
  static var _highBitIndex: Self {
    // FIXME(integers): uncomment once UInt conforms to BinaryInteger
    //return Self.init(_truncatingBits: UInt(Self.bitWidth._storage) &- 1)
    fatalError()
  }

  public var popcount: Int {
    fatalError()
  }

  public static func doubleWidthDivide(
    _ lhs: (high: Self, low: Magnitude), _ rhs: Self)
    -> (quotient: Self, remainder: Self) {
    fatalError()
  }
}

% for x in [op for ops in binaryArithmetic.values() for op in ops]:
%   callLabel = x.firstArg + ': ' if not x.firstArg == '_' else ''
%   if x.kind != '/':
public func &${x.operator} <T: FixedWidthInteger>(lhs: T, rhs: T) -> T {
  return lhs.${x.name}WithOverflow(${callLabel}rhs).partialValue
}
%   end
% end

//===----------------------------------------------------------------------===//
//===--- UnsignedInteger --------------------------------------------------===//
//===----------------------------------------------------------------------===//

public protocol UnsignedInteger_ : BinaryInteger {
  associatedtype Magnitude : BinaryInteger
}

extension UnsignedInteger_ {
  @_transparent
  public var magnitude: Self { return self }

  @_transparent
  public static var isSigned: Bool { return false }

  public var description: String {
    // FIXME(integers): uncomment once Int conforms to BinaryInteger
    fatalError()
    //if self == 0 {
      //return "0"
    //}

    //let ascii0 = 48
    //var buf: [UnicodeScalar] = []

    //var x = self
    //repeat {
      //let r = x % 10
      //x /= 10
      //buf.append(
        //UnicodeScalar(
          //ascii0 + Int(Word(extendingOrTruncating: r)._storage)))
    //}
    //while x != 0
    //return String(buf.reversed().lazy.map { Character($0) })
  }
}

extension UnsignedInteger_ where Self : FixedWidthInteger {
  @_transparent
  public init<T : BinaryInteger>(_ source: T) {
    // FIXME(integers): uncomment checks
    //_assertCond(
      //source >= 0, "negative value \(source) not representable by \(Self.self)")
    //let requiredBits = source.minimumSignedRepresentationBitWidth - 1
    //_assertCond(
      //requiredBits <= Self.bitWidth,
      //"\(Self.self) cannot store all \(requiredBits)  bits "
      //+ "needed for unsigned representation of \(source)")
    self.init(extendingOrTruncating: source)
  }

  @_transparent
  public init?<T : BinaryInteger>(exactly source: T) {
    // FIXME(integers): uncomment checks
    //_assertCond(
      //source >= 0, "negative value \(source) not representable by \(Self.self)")
    let requiredBits = source.minimumSignedRepresentationBitWidth - 1
    if requiredBits > Self.bitWidth {
      return nil
    }
    self.init(extendingOrTruncating: source)
  }

  @_transparent
  public static var max: Self {
    return ~0
  }

  @_transparent
  public static var min: Self {
    return 0
  }

}


//===----------------------------------------------------------------------===//
//===--- SignedInteger ----------------------------------------------------===//
//===----------------------------------------------------------------------===//

public protocol SignedInteger_ : BinaryInteger, SignedArithmetic {
  associatedtype Magnitude : BinaryInteger
}

extension SignedInteger_ {
  public var description: String {
    let base = String(describing: magnitude)
    return self < 0 ? "-" + base : base
  }

  @_transparent
  public static var isSigned: Bool { return true }
}

extension SignedInteger_ where Self : FixedWidthInteger {
  @_transparent
  public init<T : BinaryInteger>(_ source: T) {
    // FIXME(integers): uncomment checks
    //let requiredBits = source.minimumSignedRepresentationBitWidth
    //_assertCond(
      //requiredBits <= Self.bitWidth,
      //"\(Self.self) cannot store all \(requiredBits) bits "
      //+ "needed for signed representation of \(source)")
    self.init(extendingOrTruncating: source)
  }

  @_transparent
  public init?<T : BinaryInteger>(exactly source: T) {
    let requiredBits = source.minimumSignedRepresentationBitWidth
    if requiredBits > Self.bitWidth {
      return nil
    }
    self.init(extendingOrTruncating: source)
  }

  @_transparent
  public static var max: Self {
    return ~min
  }

  @_transparent
  public static var min: Self {
    return -1 &<< Self._highBitIndex
  }
}
